home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume22 / wp2x / part03 < prev    next >
Encoding:
Text File  |  1991-08-23  |  53.5 KB  |  1,569 lines

  1. Newsgroups: comp.sources.misc
  2. From: Raymond Chen <rjc@math.princeton.edu>
  3. Subject:  v22i057:  wp2x - WordPerfect4.2 to Whatever converter, Part03/03
  4. Message-ID: <1991Aug23.184927.9807@sparky.IMD.Sterling.COM>
  5. X-Md4-Signature: cbfc067495ccec7d7a03b00f7b44f851
  6. Date: Fri, 23 Aug 1991 18:49:27 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: Raymond Chen <rjc@math.princeton.edu>
  10. Posting-number: Volume 22, Issue 57
  11. Archive-name: wp2x/part03
  12. Environment: Amiga, MS-DOS, UNIX, ANSI-C
  13.  
  14. #! /bin/sh
  15. # This is a shell archive.  Remove anything before this line, then unpack
  16. # it by saving it into a file and typing "sh file".  To overwrite existing
  17. # files, type "sh file -c".  You can also feed this as standard input via
  18. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  19. # will see the following message at the end:
  20. #        "End of archive 3 (of 3)."
  21. # Contents:  wp2x.c
  22. # Wrapped by rjc@tomato on Wed Aug 21 00:08:06 1991
  23. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  24. if test -f 'wp2x.c' -a "${1}" != "-c" ; then 
  25.   echo shar: Will not clobber existing file \"'wp2x.c'\"
  26. else
  27. echo shar: Extracting \"'wp2x.c'\" \(51514 characters\)
  28. sed "s/^X//" >'wp2x.c' <<'END_OF_FILE'
  29. X/* $Id: wp2x.c 1.10 91/08/18 15:05:41 raymond Exp $ */
  30. X
  31. X/* Before compiling, read the section titled `portability concerns'. */
  32. X
  33. X/************************************************************************
  34. X * $Log:    wp2x.c $
  35. X * Revision 1.10  91/08/18  15:05:41  raymond
  36. X * Descriptor file stuff.
  37. X * 
  38. X * Revision 1.9  91/08/06  09:08:09  raymond
  39. X * add missing `break' in check_arity
  40. X * 
  41. X * Revision 1.8  91/08/06  08:31:21  raymond
  42. X * Avoid infinite loop if file is corrupted.
  43. X * Better error-checking on configuration file (new output scheme).
  44. X * 
  45. X * Revision 1.7  91/08/02  13:35:37  raymond
  46. X * Epsilonically better handling of environments that didn't end properly.
  47. X * Change return type of main() to keep gcc quiet.
  48. X * MSC support.
  49. X * 
  50. X * Revision 1.6  91/07/28  21:08:53  raymond
  51. X * BeginTabs et al, FNote#, ENote#, NegateTotal, more unsupported codes
  52. X * Improve character tokens, Header, Footer
  53. X * Take care when people don't end lines with HRt
  54. X * Fix major bugs in endnote processing, footnote numbering (and nobody
  55. X *    noticed!)
  56. X * More worries about signed characters.
  57. X * 
  58. X * Revision 1.5  91/07/23  22:59:43  raymond
  59. X * Add COMMENT token, and some bug fixes.
  60. X * 
  61. X * Revision 1.4  91/07/23  22:09:23  raymond
  62. X * Concessions to slightly non-ANSI compilers. (`const', `unsigned char')
  63. X * More patches for machines with signed characters.
  64. X * Fix blatant bug in hex constants.  (Amazed nobody noticed.)
  65. X * New tags SetFn#, Header, Footer.
  66. X * Warning messages for unsupported tokens.
  67. X * Backslahes processed in character tags.
  68. X * Fixed(?) footnotes, endnotes, page length changes.
  69. X * Inserted missing `break's into the huge switch.
  70. X * 
  71. X * Revision 1.3  91/07/12  15:39:44  raymond
  72. X * Spiffy Turbo C support.
  73. X * Some <stdlib.h>'s don't declare errno et al.
  74. X * Command line switches `-s' and `-n' added.
  75. X * More cute warning messages.
  76. X * Dots periodically emitted.
  77. X * Give the enum of token types a name, to placate QuickC.
  78. X * Fix problems with pitch changes and signed characters.
  79. X * 
  80. X * Revision 1.2  91/06/22  08:18:22  raymond
  81. X * <process.h> and fputchar() aren't sufficiently portable.
  82. X * strerror() fails to exist on some so-called ANSI platforms.
  83. X * Removed assumption that characters are unsigned.
  84. X * Forgot to #include <stdarg.h>
  85. X * 
  86. X */
  87. X
  88. X/************************************************************************
  89. X * PORTABILITY CONCERNS
  90. X ************************************************************************
  91. X *
  92. X * If possible, compile with unsigned characters.  (Though I think
  93. X * I've taken care of all the places where I assumed characters are
  94. X * unsigned.)
  95. X *
  96. X * This program assumes that your compiler is fully ANSI-conformant.
  97. X * Depending on how non-conformant your compiler is, you may need to
  98. X * set the following symbols at compile time:
  99. X *
  100. X * NO_CONST -- set this if your compiler does not know what `const' means.
  101. X * Cdecl    -- how to tag functions that are variadic.
  102. X *
  103. X * Cdecl is used if you need special declarations for variadic functions.
  104. X * This is used by IBM PC compilers so that you can make the default
  105. X * parameter passing Pascal-style or Fastcalls.
  106. X *
  107. X * Some very machine-dependent stuff happens when trying to open the
  108. X * descriptor file.  Please read dopen.c as well.
  109. X */
  110. X
  111. X#ifdef NO_CONST
  112. X#define const
  113. X#endif
  114. X
  115. X#ifndef Cdecl                       /* default is nothing */
  116. X#define Cdecl
  117. X#endif
  118. X
  119. X/************************************************************************
  120. X * This program divides naturally into two parts.
  121. X *
  122. X * The first part reads in the descriptor file and builds the expansions
  123. X * for each of the identifiers listed above.
  124. X * This is the easy part.
  125. X *
  126. X * The second part reads the input file and uses the expansions collected
  127. X * in the first part to transform the file into the output.
  128. X * This is the hard part.
  129. X *
  130. X ************************************************************************/
  131. X
  132. X/* And now, the code.
  133. X * We start off with some obvious header files.
  134. X */
  135. X
  136. X#include <stdio.h>
  137. X#include <stdarg.h>
  138. X#include <stdlib.h>
  139. X#include <string.h>
  140. X#include <ctype.h>
  141. X
  142. X/* Some platforms do not define these externals in stdlib.h */
  143. Xextern int   Cdecl errno;
  144. Xextern char *Cdecl sys_errlist[];
  145. Xextern int   Cdecl sys_nerr;
  146. X
  147. X/************************************************************************/
  148. X/* Some common idioms                                                   */
  149. X/************************************************************************/
  150. X
  151. X#define do_nothing /* twiddle thumbs */
  152. X
  153. X/************************************************************************/
  154. X/* Blowing up                                                           */
  155. X/************************************************************************/
  156. X
  157. X/* The function "error" accepts two arguments.  A FILE pointer and
  158. X * a printf-style argument list.  The printf-style arguments are
  159. X * printed to stderr.  If the FILE is non-NULL, the the remaining
  160. X * contents of the file are printed as well (to provide context), up
  161. X * to 80 characters.
  162. X */
  163. X
  164. Xvoid Cdecl error(FILE *fp, char *fmt, ...)
  165. X{
  166. X  int i;
  167. X  va_list ap;
  168. X
  169. X  fputs("Error: ", stderr);
  170. X  va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap);
  171. X  fputc('\n', stderr);
  172. X
  173. X  if (fp) {
  174. X    fprintf(stderr, "Unread text: ");
  175. X    for (i = 0; i < 80 && !feof(fp); i++) fputc(getc(fp), stderr);
  176. X    fputc('\n', stderr);
  177. X  }
  178. X  exit(1);
  179. X}
  180. X
  181. X/************************************************************************/
  182. X/* Command-line switches                                                */
  183. X/************************************************************************/
  184. Xint silent = 0;
  185. Xint blipinterval = 1024;                /* display blips every 1K */
  186. Xint blipcount;
  187. X
  188. X/************************************************************************/
  189. X/* Basic file manipulations                                             */
  190. X/************************************************************************/
  191. X
  192. X/* We here define a few basic functions.  Let us hope that the first
  193. X * three functions' names are self-descriptive.
  194. X */
  195. X
  196. Xint next_non_whitespace(FILE *fp)
  197. X{
  198. X  register int c;
  199. X
  200. X  while ((c = getc(fp)) != EOF && isspace(c)) do_nothing;
  201. X
  202. X  return c;
  203. X}
  204. X
  205. Xint next_non_space_or_tab(FILE *fp)
  206. X{
  207. X  register int c;
  208. X
  209. X  while ((c = getc(fp)) != EOF && (c == ' ' || c == '\t')) do_nothing;
  210. X
  211. X  return c;
  212. X}
  213. X
  214. Xvoid eat_until_newline(FILE *fp)
  215. X{
  216. X  register int c;
  217. X
  218. X  while ((c = getc(fp)) != EOF && c != '\n') do_nothing;
  219. X}
  220. X
  221. X/* The function parse_hex grabs a (no-more-than-two-character) hex
  222. X * constant.  Similarly, parse_octal does the same for octal constants.
  223. X */
  224. X
  225. Xint parse_hex(FILE *fp)
  226. X{
  227. X  register int c, value;
  228. X
  229. X  if (!isxdigit(c = toupper(getc(fp))))
  230. X    error(fp, "Expecting a hex digit");
  231. X
  232. X  if ((value = c - '0') > 9) value += '0' - 'A' + 10;
  233. X
  234. X  if (!isxdigit(c = getc(fp))) { ungetc(c, fp); return value; }
  235. X
  236. X  c = toupper(c);
  237. X  value = (value << 4) + c - '0';
  238. X  if (c > '9') value += '0' - 'A' + 10;
  239. X  return value;
  240. X}
  241. X
  242. Xint parse_octal(FILE *fp, register int c)
  243. X{
  244. X  register int value = c - '0';
  245. X
  246. X  if ( (c = getc(fp)) < '0' || c > '7') { ungetc(c, fp); return value; }
  247. X
  248. X  value = (value << 3) + c - '0';
  249. X
  250. X  if ( (c = getc(fp)) < '0' || c > '7') { ungetc(c, fp); return value; }
  251. X
  252. X  return (value << 3) + c - '0';
  253. X}
  254. X
  255. X
  256. X/************************************************************************/
  257. X/* Storing the input strings                                            */
  258. X/************************************************************************/
  259. X
  260. X/* The input strings are allocated from a large pool we set up at
  261. X * startup.  This lets us do our thing without having to fight
  262. X * with people like malloc and friends.  This method does limit
  263. X * our configuration file to 32K, however.  We hope that this is
  264. X * not a problem.  (It also means that the program can be translated
  265. X * to almost any other language without too much difficulty.)
  266. X *
  267. X * Here's how it works.
  268. X *
  269. X * "pool" is an array of POOL_SIZE characters.  The value of POOL_SIZE
  270. X * is flexible, but shouldn't exceed 65535, since that's the size of
  271. X * an IBM PC segment.  If your configuration file is more than 64K,
  272. X * then there's probably something wrong.
  273. X *
  274. X * "pool_ptr" points to the next character in "pool" that hasn't been
  275. X * used for anything yet.
  276. X *
  277. X * "top_of_pool" points one character beyond the end of pool, so we can
  278. X * see if we've run out of memory.
  279. X *
  280. X * When we want to put something into the pool, we simply store into "pool"
  281. X * and increment "pool_ptr" appropriately.
  282. X *
  283. X * Access to these variables is done through the following functions,
  284. X * implemented as macros.
  285. X *
  286. X * "anchor_string()" is called before you start throwing things into
  287. X * the pool.  It returns a pointer to the beginning of the string
  288. X * being built up.
  289. X *
  290. X * "add_to_string(c)" adds the character "c" to the string being built up.
  291. X *
  292. X * "finish_string()" gets ready for building a new string.  We check
  293. X * that we did not overflow our pool.  We pull the sneaky trick of
  294. X * a dummy else clause so that [1] "else"s match up properly if this
  295. X * is nested inside an "if" statement, [2] the semicolon gets eaten
  296. X * up correctly.
  297. X *
  298. X * "remove_string(s)" removes all strings from the one called "s" onwards.
  299. X *
  300. X */
  301. X
  302. X#define POOL_SIZE   32768U
  303. X
  304. Xchar pool[POOL_SIZE];
  305. Xchar *pool_ptr = pool;
  306. X#define top_of_pool (pool + POOL_SIZE)
  307. X
  308. X#define anchor_string() pool_ptr
  309. X#define add_to_string(c) (*pool_ptr++ = c)
  310. X#define finish_string() \
  311. X     if (pool_ptr >= top_of_pool) error(NULL, "string pool overflow."); \
  312. X     else do_nothing
  313. X#define remove_string(s) (pool_ptr = s)
  314. X
  315. X/************************************************************************/
  316. X/* Remembering the expansions                                           */
  317. X/************************************************************************/
  318. X
  319. X/* The array "expansion" contains the expansions for everything.
  320. X * Everything is initialized to NULL.
  321. X *
  322. X * We set up things as follows:
  323. X *  expansion[0..255]  contain the expansions for the possible characters.
  324. X *  expansion[256...]  contain the expansions for the special codes.
  325. X *
  326. X * Make sure this table is kept in parallel with the names[] array
  327. X *
  328. X *
  329. X */
  330. X
  331. X/*      name   value          When is it expanded? */
  332. X/*      ----    ---           -------------------- */
  333. Xenum token_type {          /* Some compilers do not like unnamed enums */
  334. X        typeout = 256,     /* Typed out as soon as it is encountered */
  335. X        BEGIN        ,     /* Before the first character of the file */
  336. X        END          ,     /* After the last character of the file   */
  337. X        Comment      ,     /* For wp2x-generated comments            */
  338. X        eComment     ,
  339. X
  340. X        PageNo       ,     /* Current page number */
  341. X        RomanPage    ,     /* Set page number (to roman numerals) */
  342. X        ArabicPage   ,     /* Set page number (to arabic) */
  343. X
  344. X        HSpace       ,     /* unbreakable space (`Hard space') */
  345. X
  346. X        Tab          ,     /* Tab character */
  347. X        BeginTabs    ,     /* Begin tab settings */
  348. X
  349. X        /* DO NOT CHANGE THE RELATIVE ORDER OF THESE FOUR TOKENS */
  350. X        SetTab       ,     /* Set normal tabstop at %d */
  351. X        SetTabCenter ,     /* Set center tabstop at %d */
  352. X        SetTabRight  ,     /* Set right-justified tab at %d */
  353. X        SetTabDecimal,     /* Set decimal tab at %d */
  354. X
  355. X        EndTabs      ,     /* End tab settings */
  356. X
  357. X        HPg          ,     /* Hard page break */
  358. X        CondEOP      ,     /* Conditional end-of-page */
  359. X        HRt          ,     /* Hard return */
  360. X        SRt          ,     /* Soft return */
  361. X
  362. X        NHyph        ,     /* Normal hyphen */
  363. X        NHyphE       ,     /* Normal hyphen at the end of a line */
  364. X        HHyph        ,     /* Hard (nonbreakable) hyphen */
  365. X        DHyph        ,     /* Discretionary hyphen */
  366. X        DHyphE       ,     /* Discretionary hyphen at the end of a line */
  367. X        NoHyphWord   ,     /* Do not hyphenate this word */
  368. X
  369. X        Marg         ,     /* Margin settings */
  370. X        TopMarg      ,     /* Set top margin */
  371. X        PageLength   ,     /* Set page length */
  372. X
  373. X        SS           ,     /* Single spacing */
  374. X        DS           ,     /* Double spacing */
  375. X        OHS          ,     /* 1.5 spacing (One and a Half Spacing) */
  376. X        TS           ,     /* Triple spacing */
  377. X        LS           ,     /* Generic line spacing */
  378. X        LPI          ,     /* set 6 or 8 LPI */
  379. X
  380. X        Bold         ,     /* Begin boldface */
  381. X        eBold        ,     /* End boldface */
  382. X        Und          ,     /* Begin underline */
  383. X        eUnd         ,     /* End underline */
  384. X        Red          ,     /* Begin redline */
  385. X        eRed         ,     /* End redline */
  386. X        Strike       ,     /* Begin strikeout */
  387. X        eStrike      ,     /* End strikeout */
  388. X        Rev          ,     /* Begin reverse video */
  389. X        eRev         ,     /* End reverse video */
  390. X
  391. X        Over         ,     /* Overstrike */
  392. X        eOver        ,     /* [mythical "end overstroke" code] */
  393. X        Sup          ,     /* Superscript */
  394. X        eSup         ,     /* [mythical "end superscript" code] */
  395. X        Sub          ,     /* Subscript */
  396. X        eSub         ,     /* [mythical "end subscript" code] */
  397. X
  398. X        UpHalfLine   ,     /* Advance printer up 1/2 line */
  399. X        DownHalfLine ,     /* Advance printer down 1/2 line */
  400. X        AdvanceToHalfLine, /* Advance to absolute vertical position */
  401. X
  402. X        Indent       ,     /* Indented paragraph */
  403. X        DIndent      ,     /* Left-and-right-indented paragraph */
  404. X        eIndent      ,     /* End indented paragraph */
  405. X        MargRel      ,     /* Margin release (unknown argument) */
  406. X
  407. X        Center       ,     /* Center current line */
  408. X        eCenter      ,     /* End centering */
  409. X        CenterHere   ,     /* Center line around current column */
  410. X        eCenterHere  ,     /* End centering */
  411. X
  412. X        Align        ,     /* Begin alignment */
  413. X        eAlign       ,     /* End alignment */
  414. X        AlignChar    ,     /* Set alignment character */
  415. X        FlushRight   ,     /* Begin flush right */
  416. X        eFlushRight  ,     /* End flush right */
  417. X
  418. X        Math         ,     /* Begin math mode */
  419. X        eMath        ,     /* End math mode */
  420. X        MathCalc     ,     /* Begin math calc mode */
  421. X        MathCalcColumn,    /* Math calc column */
  422. X
  423. X        SubTtl       ,     /* Do subtotal */
  424. X        IsSubTtl     ,     /* Subtotal entry */
  425. X        Ttl          ,     /* Do total */
  426. X        IsTtl        ,     /* Total entry */
  427. X        GrandTtl     ,     /* Do grand total */
  428. X        NegateTotal  ,     /* Negate current total */
  429. X
  430. X        Col          ,     /* Begin column mode */
  431. X        eCol         ,     /* End column mode */
  432. X
  433. X        Fn           ,     /* Begin footnote */
  434. X        eFn          ,     /* End footnote */
  435. X        En           ,     /* Begin endnote */
  436. X        eEn          ,     /* End endnote */
  437. X        SetFnNum     ,     /* Set footnote number */
  438. X        FNoteNum     ,     /* Footnote number */
  439. X        ENoteNum     ,     /* Endnote number */
  440. X        TableMarker  ,     /* Table of contents or whatever marker */
  441. X
  442. X        Hyph         ,     /* Hyphenation on */
  443. X        eHyph        ,     /*             off */
  444. X        Just         ,     /* Justification on */
  445. X        eJust        ,     /*               off */
  446. X        Wid          ,     /* Widow/orphan protection on */
  447. X        eWid         ,     /*                         off */
  448. X        HZone        ,     /* Hyphenation zone */
  449. X        DAlign       ,     /* Decimal alignment character */
  450. X
  451. X        Header       ,     /* Begin header text */
  452. X        eHeader      ,     /* End header text */
  453. X        Footer       ,     /* Begin footer text */
  454. X        eFooter      ,     /* End footer text */
  455. X
  456. X        Supp         ,     /* Suppress formatting for one page */
  457. X        CtrPg        ,     /* Center page vertically */
  458. X
  459. X        SetFont      ,     /* Change pitch or font */
  460. X        SetBin       ,     /* Select paper bin (0, 1, ...) */
  461. X
  462. X        PN           ,     /* Page number position (PN+0 through PN+8) */
  463. X
  464. X/* Internal tokens for unsupported operations */
  465. X        UnsupportedPlaceHolder = PN + 9,
  466. X        SetPageNumberColumn,
  467. X        SetTabs,
  468. X        SetUnderlineMode,
  469. X        DefineColumn,
  470. X        SetFootnoteAttributes,
  471. X        SetParagraphNumberingStyle,
  472. X        NumberedParagraph,
  473. X        BeginMarkedText,
  474. X        EndMarkedText,
  475. X        DefineMarkedText,
  476. X        DefineIndexMark,
  477. X        DefineMathColumns,
  478. X        Obsolete,
  479. X        ReservedCode,
  480. X        UnknownCode,
  481. X        LastToken
  482. X};
  483. X
  484. Xchar *expansion[LastToken];
  485. X
  486. X
  487. X/************************************************************************/
  488. X/* Naming the identifiers                                               */
  489. X/************************************************************************/
  490. X/* Extreme care must be taken to ensure that this list parallels the list
  491. X * of token names above.
  492. X */
  493. X
  494. Xtypedef struct identifier {
  495. X    char *name;
  496. X    int arity;
  497. X} Identifier;
  498. X
  499. XIdentifier names[] = {
  500. X    { "typeout", 0 },
  501. X    { "BEGIN", 0 },
  502. X    { "END", 0 },
  503. X    { "Comment", 0 },
  504. X    { "comment", 0 },
  505. X    { "PageNo", 0 },
  506. X    { "RomanPage", 1 },
  507. X    { "ArabicPage", 1 },
  508. X    { "HSpace", 0 },
  509. X    { "Tab", 0 },
  510. X    { "BeginTabs", 0 },
  511. X    { "SetTab", 1 },
  512. X    { "SetTabCenter", 1 },
  513. X    { "SetTabRight", 1 },
  514. X    { "SetTabDecimal", 1 },
  515. X    { "EndTabs", 0 },
  516. X    { "HPg", 0 },
  517. X    { "CondEOP", 1 },
  518. X    { "HRt", 0 },
  519. X    { "SRt", 0 },
  520. X    { "-", 0 },        /* NHyph */
  521. X    { "--", 0 },       /* NHyphE */
  522. X    { "=", 0 },        /* HHyph */
  523. X    { "\\-", 0 },      /* DHyph */
  524. X    { "\\--", 0 },     /* DHyphE */
  525. X    { "NoHyphWord", 0 },
  526. X    { "Marg", 2 },
  527. X    { "TopMarg", 1 },
  528. X    { "PageLength", 1 },
  529. X    { "SS", 0 },
  530. X    { "DS", 0 },
  531. X    { "1.5S", 0 },    /* OHS */
  532. X    { "TS", 0 },
  533. X    { "LS", 1 },
  534. X    { "LPI", 1 },
  535. X    { "Bold", 0 },
  536. X    { "bold", 0 },
  537. X    { "Und", 0 },
  538. X    { "und", 0 },
  539. X    { "Red", 0 },
  540. X    { "red", 0 },
  541. X    { "Strike", 0 },
  542. X    { "strike", 0 },
  543. X    { "Rev", 0 },
  544. X    { "rev", 0 },
  545. X    { "Over", 0 },
  546. X    { "over", 0 },
  547. X    { "Sup", 0 },
  548. X    { "sup", 0 },
  549. X    { "Sub", 0 },
  550. X    { "sub", 0 },
  551. X    { "UpHalfLine", 0 },
  552. X    { "DownHalfLine", 0 },
  553. X    { "AdvanceToHalfLine", 2 },
  554. X    { "Indent", 0 },
  555. X    { "DIndent", 0 },
  556. X    { "indent", 0 },
  557. X    { "MarginRelease", 1 },
  558. X    { "Center", 0 },
  559. X    { "center", 0 },
  560. X    { "CenterHere", 0 },
  561. X    { "centerhere", 0 },
  562. X    { "Align", 0 },
  563. X    { "align", 0 },
  564. X    { "AlignChar", 1 },
  565. X    { "FlushRight", 0 },
  566. X    { "flushright", 0 },
  567. X    { "Math", 0 },
  568. X    { "math", 0 },
  569. X    { "MathCalc", 0 },
  570. X    { "MathCalcColumn", 0 },
  571. X    { "SubTotal", 0 },
  572. X    { "IsSubTotal", 0 },
  573. X    { "Total", 0 },
  574. X    { "IsTotal", 0 },
  575. X    { "GrandTotal", 0 },
  576. X    { "NegateTotal", 0 },
  577. X    { "Col", 0 },
  578. X    { "col", 0 },
  579. X    { "Fn", 0 },
  580. X    { "fn", 0 },
  581. X    { "En", 0 },
  582. X    { "en", 0 },
  583. X    { "SetFn#", 1 },
  584. X    { "FNote#", 0 },
  585. X    { "ENote#", 0 },
  586. X    { "TableMarker", 0 },
  587. X    { "Hyph", 0 },
  588. X    { "hyph", 0 },
  589. X    { "Just", 0 },
  590. X    { "just", 0 },
  591. X    { "Wid", 0 },
  592. X    { "wid", 0 },
  593. X    { "HZone", 2 },
  594. X    { "DAlign", 1 },
  595. X    { "Header", 0 },
  596. X    { "header", 0 },
  597. X    { "Footer", 0 },
  598. X    { "footer", 0 },
  599. X    { "Supp", 1 },
  600. X    { "CtrPg", 0 },
  601. X    { "SetFont", 2 },
  602. X    { "SetBin", 1 },
  603. X    { "PN0", 0 },
  604. X    { "PN1", 0 },
  605. X    { "PN2", 0 },
  606. X    { "PN3", 0 },
  607. X    { "PN4", 0 },
  608. X    { "PN5", 0 },
  609. X    { "PN6", 0 },
  610. X    { "PN7", 0 },
  611. X    { "PN8", 0 },
  612. X    { NULL, 0 },  /* UnsupportedPlaceHolder -- keeps match_identifier happy */
  613. X    { "set page number column", 0 },
  614. X    { "extended tabs", 0 },
  615. X    { "underline mode", 0 },
  616. X    { "define column", 0 },
  617. X    { "footnote attributes", 0 },
  618. X    { "paragraph numbering style", 0 },
  619. X    { "numbered paragraph", 0 },
  620. X    { "begin marked text", 0 },
  621. X    { "end marked text", 0 },
  622. X    { "define marked text", 0 },
  623. X    { "define index mark", 0 },
  624. X    { "define math columns", 0 },
  625. X    { "WPCorp obsolete", 0 },
  626. X    { "WPCorp reserved", 0 },
  627. X    { "WPCorp undefined", 0 },
  628. X};
  629. X
  630. X/* The file pointer "descriptor" points to our descriptor file
  631. X * and "input" points to our input file.
  632. X *
  633. X * Kinda makes sense that way.
  634. X */
  635. X
  636. XFILE *descriptor, *input;
  637. X
  638. X/* And the function match_identifier(s) takes a string and converts
  639. X * it to its corresponding integer.  Or blows up if it couldn't
  640. X * find one.
  641. X */
  642. X
  643. Xint match_identifier(const char *s)
  644. X{
  645. X  Identifier *I;
  646. X
  647. X  /* Maybe it is a special character */
  648. X  if (s[0] == '\'' && s[2] == '\'' && s[3] == '\0')
  649. X    return (int) (unsigned char) s[1];
  650. X
  651. X  /* Else it must be a multi-character guy */
  652. X  for (I = names; I->name; I++)
  653. X    if (!strcmp(I->name, s)) return typeout + (I - names);
  654. X
  655. X  /* Otherwise, I don't know what to do with it */
  656. X  error(descriptor, "Unknown identifier %s", s);
  657. X  /*NOTREACHED*/
  658. X  return 0;
  659. X}
  660. X
  661. X/* check_arity ensures that the expansion string is valid */
  662. Xvoid check_arity(int ident, char *t)
  663. X{
  664. X  char *s;
  665. X  int arity = 0;
  666. X  if (ident > typeout) arity = names[ident-typeout].arity;
  667. X  for (s = t; *s; s++) {
  668. X    if (*s != '%') continue;
  669. X    switch (*++s) {
  670. X    case '\n':
  671. X      if (s != t+1)
  672. X        error(descriptor, "%s: `%%\\n' not at start of expansion",
  673. X              names[ident-typeout].name);
  674. X        break;
  675. X    case '1':
  676. X    case 'c':
  677. X      if (arity < 1) goto bad_escape;
  678. X      break;
  679. X    case '2':
  680. X      if (arity < 2) goto bad_escape;
  681. X      break;
  682. X    case '%':
  683. X      break;
  684. X    default:
  685. Xbad_escape:
  686. X      error(descriptor, "%s: invalid escape `%%%c'", names[ident-typeout].name, *s);
  687. X    }
  688. X  }
  689. X}
  690. X
  691. X/************************************************************************/
  692. X/* Reading input from the descriptor file                               */
  693. X/************************************************************************/
  694. X
  695. X/* The macro igetc() gets a character from the input file.
  696. X * the macro dgetc() gets a character from the descriptor file.
  697. X*/
  698. X
  699. X#define igetc() getc(input)
  700. X#define dgetc() getc(descriptor)
  701. X
  702. X/* expand_backslash() is called when a backslash is encountered in
  703. X * the descriptor file.  Its job is to parse a backslash-sequence.
  704. X * The usual C-escapes (\a \b \f \n \r \t \v) are understood, as
  705. X * well as the octal escape \000 [up to three octal digits] and
  706. X * the hex escape \xFF [up to two hex digits].
  707. X */
  708. X
  709. Xint expand_backslash(void) {
  710. X    int c;
  711. X
  712. X    switch (c = dgetc()) {
  713. X    case 'a': c = '\a'; break;
  714. X    case 'b': c = '\b'; break;
  715. X    case 'f': c = '\f'; break;
  716. X    case 'n': c = '\n'; break;
  717. X    case 'r': c = '\r'; break;
  718. X    case 't': c = '\t'; break;
  719. X    case 'v': c = '\v'; break;
  720. X    case 'x':
  721. X    case 'X': c = parse_hex(descriptor); break;
  722. X    case '0':
  723. X    case '1':
  724. X    case '2':
  725. X    case '3':
  726. X    case '4':
  727. X    case '5':
  728. X    case '6':
  729. X    case '7': c = parse_octal(descriptor, c); break;
  730. X    default:  /* c = c; */ break;
  731. X    }
  732. X    return c;
  733. X}
  734. X
  735. X/* The function read_identifier() attempts to match an identifier
  736. X * in the descriptor file.  It returns EOF if the end of the descriptor
  737. X * file was reached, or the code of the identifier we found.
  738. X * (or blows up if an error was detected.)
  739. X * We build the identifier in "s", with the help of our
  740. X * pool-managing functions above, then discard it, immediately,
  741. X * since we don't use it any more.
  742. X */
  743. X
  744. Xint read_identifier(void)
  745. X{
  746. X  register int c;      /* A character we have read */
  747. X  char *s;    /* The identifier we are building */
  748. X  int ident;   /* The identifier we found */
  749. X
  750. X  /* Skip over comments */
  751. X  while ((c = next_non_whitespace(descriptor)) == '#')
  752. X      eat_until_newline(descriptor);
  753. X
  754. X  if (c == EOF) return EOF;
  755. X
  756. X  /* At this point, "c" contains the first letter of a potential
  757. X   * identifier.  Let's see what it could possibly be.
  758. X   */
  759. X  s = anchor_string();
  760. X  if (c == '\'') {                      /* a character token */
  761. X    add_to_string(c);
  762. X    if ((c = dgetc()) == '\\') c = expand_backslash();
  763. X    add_to_string(c);
  764. X    if ((c = dgetc()) != '\'')
  765. X      error(descriptor, "Invalid character identifier");
  766. X    add_to_string(c);
  767. X    c = next_non_space_or_tab(descriptor);
  768. X  } else do {                           /* a name token */
  769. X    add_to_string(c);
  770. X    c = next_non_space_or_tab(descriptor);
  771. X    if (c == '\\') c = expand_backslash();
  772. X  } while (c != EOF && c != '=' && c != '\n');
  773. X
  774. X  if (c != '=') error(descriptor, "Identifier not followed by = sign");
  775. X      /* A boo-boo.  Something bad happened. */
  776. X
  777. X  add_to_string('\0');   /* Make it a standard C string. */
  778. X  finish_string();
  779. X
  780. X  ident = match_identifier(s); /* Go find one. */
  781. X
  782. X  remove_string(s); /* And we're done with it now. */
  783. X
  784. X  return ident;
  785. X}
  786. X
  787. X/* The function grab_expansion() reads expansion text from the
  788. X * descriptor file and adds it to the pool, returning a pointer
  789. X * to the string it just created.
  790. X *
  791. X * After anchoring a new string, we look for the opening quotation
  792. X * mark, then start gobbling characters.  Everything gets copied
  793. X * straight into the string.
  794. X *
  795. X */
  796. X
  797. Xchar *grab_expansion(void)
  798. X{
  799. X  register int c; /* Characters being read */
  800. X  char *s;   /* The string we are building */
  801. X
  802. X  s = anchor_string();
  803. X
  804. X  if (next_non_whitespace(descriptor) != '\"')
  805. X    error(descriptor, "Quotation mark expected");
  806. X
  807. X  /* Now read the stream until we hit another quotation mark. */
  808. X
  809. X  while ((c = dgetc()) != EOF && c != '\"') {
  810. X    if (c == '\\') c = expand_backslash();
  811. X    add_to_string(c);
  812. X  }
  813. X  add_to_string('\0');
  814. X  finish_string();
  815. X  return s;
  816. X}
  817. X
  818. X/* Ah, now with all of these beautiful functions waiting for us,
  819. X * we can now write our first Useful Function:  do_descriptor_file.
  820. X * It reads the descriptor file and loads up the "expansion" array
  821. X * with the text expansions we are reading from the file.
  822. X *
  823. X * If we grabbed the expansion of a "typeout", we type it out
  824. X * and discard the string.
  825. X *
  826. X * We stop when the descriptor file runs dry.
  827. X *
  828. X */
  829. X
  830. Xvoid do_descriptor_file(void)
  831. X{
  832. X  register int ident;
  833. X
  834. X  while ((ident = read_identifier()) != EOF) {
  835. X    expansion[ident] = grab_expansion();
  836. X    if (ident == typeout && !silent) {
  837. X      fputs(expansion[typeout], stderr); remove_string(expansion[typeout]);
  838. X      expansion[typeout] = NULL;
  839. X    } else check_arity(ident, expansion[ident]);
  840. X  }
  841. X}
  842. X
  843. X/************************************************************************/
  844. X/* Reading from the input file                                          */
  845. X/************************************************************************/
  846. X
  847. X/* The function verify(c) checks that the next character in the input
  848. X * stream is indeed "c".  It eats the character, if all is well.
  849. X * If something went wrong, we complain to stderr, but keep going.
  850. X */
  851. X
  852. Xvoid verify(int c)
  853. X{
  854. X  int d = igetc();
  855. X  if (d != c) fprintf(stderr, "Warning: Expected %02X but received %02X.\n", c, d);
  856. X}
  857. X
  858. X/* The function gobble(n) simply eats "n" characters from the input
  859. X * file.
  860. X */
  861. Xvoid gobble(int n)
  862. X{
  863. X  while (n--) (void) igetc();
  864. X}
  865. X
  866. Xint last_HRt = 0;                       /* most recent output was HRt */
  867. X
  868. X/* Processing a special code simply entails dumping its expansion.
  869. X * If the expansion is NULL, then we either
  870. X *   [1] print nothing, if it is a code,
  871. X *   [2] print the character itself, if it is an ASCII character.
  872. X *
  873. X * In dumping its expansion, we expand the following percent-escapes:
  874. X *
  875. X *  The percent-escapes are:
  876. X *      %\n  -- newline if previous character was not a newline
  877. X *              (meaningful only as first character in sequence)
  878. X *      %1   -- first parameter, in decimal form
  879. X *      %2   -- second parameter, in decimal form
  880. X *      %c   -- first parameter, in character form
  881. X *      %%   -- literal percent sign
  882. X *
  883. X *  all other %-escapes are flagged as warnings (but should never occur,
  884. X *  since they are trapped at the time the descriptor file is read.)
  885. X */
  886. Xvoid process(int c, int d1, int d2)
  887. X{
  888. X  char *s;
  889. X  static int last_newline = 0;
  890. X
  891. X  last_HRt = 0;                         /* the killer switch sets this */
  892. X
  893. X  if (expansion[c] == NULL) {           /* invent a default action */
  894. X    if (c >= ' ' && c < 128) {
  895. X      putchar(c);                       /* regular characters emit themselves */
  896. X      last_newline = 0;
  897. X      return;
  898. X    } else if (c < 256) {               /* single character */
  899. X      expansion[c] = anchor_string(); /* emits itself */
  900. X      add_to_string(c); add_to_string('\0');
  901. X      finish_string();
  902. X      if (!silent) fprintf(stderr, "Warning: No expansion for %02X (%c)\n", c, c);
  903. X    } else {                            /* provide null expansion */
  904. X      expansion[c] = "";
  905. X      if (!silent) {
  906. X        fprintf(stderr, "Warning: No expansion for %s\n", names[c-typeout].name);
  907. X      }
  908. X    }
  909. X  }
  910. X
  911. X  s = expansion[c];
  912. X  if (!*s) return;    /* the rest of the code assumes non-null string */
  913. X  do {
  914. X    if (*s != '%') putchar(*s++);
  915. X    else {
  916. X      s++;
  917. X      switch (*s++) {
  918. X      case '\n':
  919. X        if (!last_newline) putchar('\n'); break;
  920. X      case '1':
  921. X        printf("%d", d1); break;
  922. X      case '2':
  923. X        printf("%d", d2); break;
  924. X      case 'c':
  925. X        putchar(d1); break;
  926. X      case '%':
  927. X        putchar('%'); break;
  928. X      default:
  929. X        fprintf(stderr, "Internal error:  Invalid escape, %%%c\n", s[-1]);
  930. X        break;
  931. X      }
  932. X    }
  933. X  } while (*s);
  934. X  last_newline = s[-1] == '\n';
  935. X}
  936. X
  937. X#define process0(c)     process(c,0,0)
  938. X#define process1(c,a)   process(c,a,0)
  939. X#define process2(c,a,b) process(c,a,b)
  940. X
  941. Xvoid unsupported(int c)
  942. X{
  943. X  if (!silent && !expansion[c]) {
  944. X    expansion[c] = "";
  945. X    fprintf(stderr, "Warning: `%s' code not supported\n", names[c-typeout].name);
  946. X  }
  947. X  process0(Comment); fputs(names[c-typeout].name, stdout); process0(eComment);
  948. X}
  949. X
  950. X/* The function gobble_until(c) eats characters from the input file
  951. X * until it reaches a c or reaches EOF.
  952. X */
  953. Xvoid gobble_until(int c)
  954. X{
  955. X  int i;
  956. X  while ((i = igetc()) != EOF && (int) (unsigned char) i != c) do_nothing;
  957. X}
  958. X
  959. X/* line_spacing(l) is called whenever we hit a line-spacing-change command.
  960. X * The argument is the desired line spacing, multiplied by two.
  961. X * So single spacing gets a 2, 1.5 spacing gets a 3, etc.
  962. X */
  963. Xvoid line_spacing(int l)
  964. X{
  965. X  switch (l) {
  966. X    case 2: process0(SS); break;
  967. X    case 3: process0(OHS); break;
  968. X    case 4: process0(DS); break;
  969. X    case 6: process0(TS); break;
  970. X    default: process1(LS, l); break;
  971. X  }
  972. X}
  973. X
  974. Xint environment_status = 0;             /* cleanup at HRt */
  975. Xvoid leave_environment(int force_HRt) {
  976. X    if (environment_status) {
  977. X      process0(environment_status);
  978. X      environment_status = 0;
  979. X    }
  980. X    if (force_HRt && !last_HRt) process0(HRt);
  981. X}
  982. X
  983. X/* The "note_status" flag has one of three values:
  984. X *    0   if we are not inside a note
  985. X *    1   if we are inside a footnote
  986. X *    2   if we are inside an endnote
  987. X *
  988. X * The function handle_note() is called to deal with footnotes and
  989. X * endnotes.  It adjusts the note_status accordingly.
  990. X */
  991. X
  992. Xint note_status = 0;
  993. X
  994. Xvoid handle_note(void)
  995. X{
  996. X  if (note_status) {
  997. X    leave_environment(1); process0(note_status); note_status = 0;
  998. X  } else {          /* Decide whether it is an endnote or a footnote */
  999. X    if (igetc() & 2)  { process0(En); note_status = eEn; gobble(5); }
  1000. X                else  { process0(Fn); note_status = eFn; gobble(7); }
  1001. X    verify(0xFF);
  1002. X    gobble(2);                                  /* margins */
  1003. X  }
  1004. X}
  1005. X
  1006. X/* The tab_table is a bit field.  Each set bit represents a tabstop.
  1007. X * Note, however, that the bits are counted from MSB to LSB.
  1008. X *
  1009. X * The tab_attribute_table is a nybble field.  The n'th nybble represents
  1010. X * the attributes of the n'th tabstop.
  1011. X */
  1012. Xunsigned char tab_table[32];
  1013. Xunsigned char tab_attribute_table[20];
  1014. Xint next_attribute;
  1015. X
  1016. Xvoid process_tab_attribute(int i) {
  1017. X    int b;
  1018. X
  1019. X    if (next_attribute & 1) b = tab_attribute_table[next_attribute/2] & 3;
  1020. X    else b = (tab_attribute_table[next_attribute/2] / 16) & 3;
  1021. X    next_attribute++;
  1022. X
  1023. X    /* Bottom two bites define what kind of tab.
  1024. X     * Bit 2 is set if we need dot filling.
  1025. X     * Bit 3 is unused.
  1026. X     * We `&3' above because we won't support dot filling.
  1027. X     */
  1028. X    process1(SetTab + b, i);
  1029. X}
  1030. X
  1031. Xvoid process_tab_table(void) {
  1032. X    int i;
  1033. X    next_attribute = 0;
  1034. X
  1035. X    process0(BeginTabs);
  1036. X    for (i = 0; i < 32; i++) {
  1037. X        if (tab_table[i] == 0) continue;    /* early out */
  1038. X        if (tab_table[i] & 0x80) process_tab_attribute(i * 8 + 0);
  1039. X        if (tab_table[i] & 0x40) process_tab_attribute(i * 8 + 1);
  1040. X        if (tab_table[i] & 0x20) process_tab_attribute(i * 8 + 2);
  1041. X        if (tab_table[i] & 0x10) process_tab_attribute(i * 8 + 3);
  1042. X        if (tab_table[i] & 0x08) process_tab_attribute(i * 8 + 4);
  1043. X        if (tab_table[i] & 0x04) process_tab_attribute(i * 8 + 5);
  1044. X        if (tab_table[i] & 0x02) process_tab_attribute(i * 8 + 6);
  1045. X        if (tab_table[i] & 0x01) process_tab_attribute(i * 8 + 7);
  1046. X    }
  1047. X    process0(EndTabs);
  1048. X}
  1049. X
  1050. Xvoid handle_tabs(void) {
  1051. X    /* pad the tables to force no new tabs, and left tabs everywhere */
  1052. X    memset(tab_table, 0, sizeof(tab_table));
  1053. X    memset(tab_attribute_table, 0, sizeof(tab_attribute_table));
  1054. X
  1055. X    fread(tab_table, 20, 1, input);     /* old-style tabs */
  1056. X    process_tab_table();
  1057. X}
  1058. X
  1059. Xvoid handle_extended_tabs(void) {
  1060. X    fread(tab_table, 32, 1, input);
  1061. X    fread(tab_attribute_table, 20, 1, input);
  1062. X    process_tab_table();
  1063. X}
  1064. X
  1065. X/* The FF_status flag tells us what we should do when we encounter an 0xFF.
  1066. X * It contains the token code of the active code, or 0 if no code is active.
  1067. X */
  1068. X
  1069. Xint FF_status = 0;
  1070. X
  1071. Xvoid handle_FF(void)
  1072. X{
  1073. X    if (FF_status) {                            /* finish header/footer */
  1074. X        leave_environment(1);
  1075. X        process0(FF_status);
  1076. X        gobble(2);
  1077. X        verify(0xD1);
  1078. X        FF_status = 0;
  1079. X    } else process0(0xFF);
  1080. X}
  1081. X
  1082. X/* The function process_token does all of the real work.
  1083. X * Given the first character of a token, we eat up everything
  1084. X * that belongs to that token.  This routine might be called
  1085. X * recursively, since some tokens are defined in terms of other
  1086. X * tokens.  (For example, the subscript code is expanded as
  1087. X *   [Sub] <character being subscripted> [sub]
  1088. X * and the <character being subscripted> might involve other token
  1089. X * expansions; specifically, it might be an IBM Extended character.)
  1090. X *
  1091. X * Luckily, most of our tokens are not recursive.  The macro
  1092. X *     bracket(before, after)
  1093. X * does the recursive stuff for us, bracketing the next token
  1094. X * between expansions of "before" and "after".
  1095. X *
  1096. X */
  1097. X
  1098. X#define bracket(before,after) process0(before); process_token(); \
  1099. X                              process0(after);
  1100. X
  1101. Xint process_token(void)
  1102. X{
  1103. X  int c = igetc();
  1104. X
  1105. X  if (c == EOF) return 0;
  1106. X
  1107. X  c = (int) (unsigned char) c;
  1108. X
  1109. X  if (!--blipcount && !silent) {
  1110. X    blipcount = blipinterval;
  1111. X    putc('.', stderr);
  1112. X  }
  1113. X
  1114. X  switch (c) {   /* Codes listed in numerical rather than logical order */
  1115. X
  1116. X   case 0x02: process0(PageNo); break;                   /* Page number */
  1117. X
  1118. X   case 0x09: process0(Tab); break;                    /* Tab character */
  1119. X
  1120. X   case 0x8C:                            /* Soft page break after a HRt */
  1121. X   case 0x0A:                                            /* Hard Return */
  1122. X              last_HRt = 0; leave_environment(1); last_HRt = 1; break;
  1123. X   case 0x0B:                            /* Soft page break after a SRt */
  1124. X   case 0x0D: process0(SRt); break;                      /* Soft Return */
  1125. X
  1126. X   case 0x0C: process0(HPg); break;                        /* Hard Page */
  1127. X
  1128. X   case '-' : process0(HHyph); break;             /* Nonbreaking hyphen */
  1129. X
  1130. X   case 0x80: break;                                             /* NOP */
  1131. X   case 0x81: process0(Just); break;             /* Right justification */
  1132. X   case 0x82: process0(eJust); break;                   /* Ragged right */
  1133. X   case 0x83:                                          /* End centering */
  1134. X   case 0x84: leave_environment(0); break;          /* End aligned text */
  1135. X   case 0x85: process0(MathCalc); break;             /* Begin math calc */
  1136. X   case 0x86: process0(CtrPg); break;         /* Center page vertically */
  1137. X   case 0x87: process0(Col); break;                /* Begin column mode */
  1138. X   case 0x88: process0(eCol); break;                 /* End column mode */
  1139. X   case 0x89: process0(Tab); break;           /* Tab after right margin */
  1140. X   case 0x8A: process0(Wid); break;          /* Widow/orphan protection */
  1141. X   case 0x8B: process0(eWid); break;            /* Allow widows/orphans */
  1142. X/* case 0x8C: see 0x0A */
  1143. X   case 0x8D:                                /* Footnote/Endnote number */
  1144. X              process0(note_status == eFn ? FNoteNum : ENoteNum); break;
  1145. X   case 0x8E:
  1146. X   case 0x8F: unsupported(ReservedCode); break;       /* Reserved codes */
  1147. X   case 0x90: process0(Red); break;                    /* Begin redline */
  1148. X   case 0x91: process0(eRed); break;                     /* End redline */
  1149. X   case 0x92: process0(Strike); break;               /* Begin strikeout */
  1150. X   case 0x93: process0(eStrike); break;                /* End strikeout */
  1151. X   case 0x94: process0(Und); break;                /* Begin underlining */
  1152. X   case 0x95: process0(eUnd); break;                 /* End underlining */
  1153. X   case 0x96: process0(Rev); break;              /* Begin reverse video */
  1154. X   case 0x97: process0(eRev); break;               /* End reverse video */
  1155. X   case 0x98: process0(TableMarker); break;/* Table of something marker */
  1156. X   case 0x99: bracket(Over, eOver); break;                /* Overstrike */
  1157. X   case 0x9A: process0(NoHyphWord); break;/* Do not hyphenate this word */
  1158. X   case 0x9B: break;                           /* End of generated text */
  1159. X   case 0x9C: process0(eBold); break;                   /* End boldface */
  1160. X   case 0x9D: process0(Bold); break;                  /* Begin boldface */
  1161. X   case 0x9E: process0(eHyph); break;             /* Forbid hyphenation */
  1162. X   case 0x9F: process0(Hyph); break;               /* Allow hyphenation */
  1163. X   case 0xA0: process0(HSpace); break;                    /* Hard space */
  1164. X   case 0xA1: process0(SubTtl); break;                   /* Do subtotal */
  1165. X   case 0xA2: process0(IsSubTtl); break;              /* Subtotal entry */
  1166. X   case 0xA3: process0(Ttl); break;                         /* Do total */
  1167. X   case 0xA4: process0(IsTtl); break;                    /* Total entry */
  1168. X   case 0xA5: process0(GrandTtl); break;              /* Do grand total */
  1169. X   case 0xA6: process0(MathCalcColumn); break;      /* Math calc column */
  1170. X   case 0xA7: process0(Math); break;                 /* Begin math mode */
  1171. X   case 0xA8: process0(eMath); break;                  /* End math mode */
  1172. X   case 0xA9: process0(NHyph); break;        /* Normal breakable hyphen */
  1173. X   case 0xAA:                                  /* Hyphen at end of line */
  1174. X   case 0xAB: process0(NHyphE); break;         /* Hyphen at end of page */
  1175. X   case 0xAC: process0(DHyph); break;           /* Discretionary hyphen */
  1176. X   case 0xAD:                           /* Discretionary hyphen at EOLn */
  1177. X   case 0xAE: process0(DHyphE); break;  /* Discretionary hyphen at EOPg */
  1178. X   case 0xAF:                                   /* EOT columns and EOLn */
  1179. X   case 0xB0: break;                            /* EOT columns and EOPg */
  1180. X
  1181. X   case 0xB1: process0(NegateTotal); break;     /* Negate current total */
  1182. X
  1183. X   case 0xBC: bracket(Sup, eSup); break;                 /* Superscript */
  1184. X   case 0xBD: bracket(Sub, eSub); break;                   /* Subscript */
  1185. X   case 0xBE: process0(UpHalfLine); break;       /* Advance 1/2 line up */
  1186. X   case 0xBF: process0(DownHalfLine); break;   /* Advance 1/2 line down */
  1187. X
  1188. X   case 0xC0: gobble(2); c = igetc();                  /* Margin change */
  1189. X              process2(Marg, c, igetc()); verify(0xC0); break;
  1190. X
  1191. X   case 0xC1: gobble(1); line_spacing(igetc()); verify(0xC1); break;
  1192. X                                                 /* Line spacing change */
  1193. X
  1194. X   case 0xC2: process1(MargRel, igetc());             /* Margin release */
  1195. X              verify(0xC2); break;
  1196. X
  1197. X
  1198. X   case 0xC3:                                            /* Center text */
  1199. X              leave_environment(0);
  1200. X              switch (igetc()) {
  1201. X              case 0: process0(Center);       /* Center between margins */
  1202. X                      environment_status = eCenter; break;
  1203. X              case 1:                   /* Center around current column */
  1204. X                      process0(CenterHere);
  1205. X                      environment_status = eCenterHere; break;
  1206. X              }
  1207. X              gobble(2); verify(0xC3); break;
  1208. X
  1209. X   case 0xC4:                                   /* Align or Flush Right */
  1210. X              leave_environment(0);
  1211. X              c = igetc();
  1212. X              /* if high bit on c is set, then dot fill.  (Ignore)      */
  1213. X              switch (c & 0x7f) {
  1214. X              case 0x0C:
  1215. X              case 0x0A: process1(FlushRight, igetc());/* alignment col */
  1216. X                         environment_status = eFlushRight;
  1217. X                         break;
  1218. X              default:   process2(Align, c, igetc());/* alignment column */
  1219. X                         environment_status = eAlign;
  1220. X                         break;
  1221. X              }
  1222. X              gobble(1);                                       /* trash */
  1223. X              verify(0xC4);
  1224. X              break;
  1225. X
  1226. X   case 0xC5: gobble(2); c = igetc();               /* Hyphenation zone */
  1227. X              process2(HZone, c, igetc()); verify(0xC5); break;
  1228. X
  1229. X   case 0xC6: gobble(1);                        /* Page number position */
  1230. X              process0(PN + igetc()); verify(0xC6); break;
  1231. X
  1232. X   case 0xC7: gobble(2); c = igetc();                /* New page number */
  1233. X              c = (c<<8) + (unsigned char)igetc();
  1234. X              process1( (c&0x8000) ? RomanPage : ArabicPage, c&0x7fff);
  1235. X              verify(0xC7); break;
  1236. X
  1237. X   case 0xC8: gobble(3);                      /* Set Page number column */
  1238. X              /* next 3 bytes are <left> <center> <right> */
  1239. X              gobble(3);
  1240. X              unsupported(SetPageNumberColumn);
  1241. X              verify(0xC8); break;
  1242. X
  1243. X   case 0xC9: gobble(20);                                   /* Set tabs */
  1244. X              handle_tabs();
  1245. X              verify(0xC9); break;
  1246. X
  1247. X   case 0xCA: process1(CondEOP, igetc());    /* Conditional end of page */
  1248. X              verify(0xCA); break;
  1249. X
  1250. X   case 0xCB:                                      /* Set pitch or font */
  1251. X              gobble(2);                          /* old pitch and font */
  1252. X              c = igetc();
  1253. X              process2(SetFont, c, igetc());   /* pitch and font number */
  1254. X                              /* negative pitch means proportional font */
  1255. X              verify(0xCB); break;
  1256. X
  1257. X   case 0xCC:                                     /* Indented paragraph */
  1258. X              leave_environment(0);
  1259. X              gobble(1); process1(Indent, igetc()); verify(0xCC);
  1260. X              environment_status = eIndent; break;
  1261. X                                          /* (really: Temporary margin) */
  1262. X
  1263. X   case 0xCD:                          /* Indented paragraph (obsolete) */
  1264. X              leave_environment(0);
  1265. X              process1(Indent, igetc()); verify(0xCD);
  1266. X              environment_status = eIndent; break;
  1267. X                                          /* (really: Temporary margin) */
  1268. X
  1269. X   case 0xCE: gobble(1); process1(TopMarg, igetc());  /* Set top margin */
  1270. X              verify(0xCE); break;
  1271. X
  1272. X   case 0xCF:                 /* Suppress headers/footers for this page */
  1273. X              process1(Supp, (unsigned char)igetc());
  1274. X              verify(0xCF); break;
  1275. X
  1276. X   case 0xD0: gobble(2); /* old form length */       /* Set page length */
  1277. X              process1(PageLength, igetc());          /* lines per page */
  1278. X              gobble(1);                             /* new page length */
  1279. X              verify(0xD0); break;
  1280. X
  1281. X   case 0xD1:                                          /* header/footer */
  1282. X              c = igetc();                                  /* def byte */
  1283. X              gobble(1);                              /* old half-lines */
  1284. X              if (c&2) { process0(Footer); FF_status = eFooter; }
  1285. X                  else { process0(Header); FF_status = eHeader; }
  1286. X              verify(0xFF); verify(0xFF);                  /* separator */
  1287. X              gobble(2);                       /* left and right margin */
  1288. X              break;                             /* continue processing */
  1289. X
  1290. X   case 0xD2: gobble(5);                           /* obsolete footnote */
  1291. X              unsupported(Obsolete);
  1292. X              gobble_until(0xD2);
  1293. X              break;
  1294. X
  1295. X   case 0xD3: gobble(2);              /* obsolete `set footnote number' */
  1296. X              unsupported(Obsolete);
  1297. X              verify(0xD3);
  1298. X              break;
  1299. X
  1300. X   case 0xD4:                            /* Advance to half line number */
  1301. X              c = igetc(); /* current line number */
  1302. X              process2(AdvanceToHalfLine, c, igetc());/* desired line # */
  1303. X              verify(0xD4); break;
  1304. X
  1305. X   case 0xD5: gobble(1); process1(LPI, igetc());    /* Set LPI (6 or 8) */
  1306. X              verify(0xD5); break;
  1307. X
  1308. X   case 0xD6:                                      /* set extended tabs */
  1309. X              /* next 4 bytes are <old start><old increment>
  1310. X                                  <new start><new increment> */
  1311. X              gobble(4);
  1312. X              unsupported(SetTabs);
  1313. X              verify(0xD6); break;
  1314. X
  1315. X   case 0xD7: gobble(63);                        /* Define math columns */
  1316. X              unsupported(DefineMathColumns);
  1317. X              verify(0xD7); break;
  1318. X
  1319. X   case 0xD8: gobble(1); process1(AlignChar, igetc());
  1320. X              verify(0xD8); break;           /* Set alignment character */
  1321. X
  1322. X   case 0xD9: gobble(2);                     /* obsolete margin release */
  1323. X              unsupported(Obsolete);
  1324. X              verify(0xD9);
  1325. X              break;
  1326. X
  1327. X   case 0xDA: gobble(1+1);                        /* Set underline mode */
  1328. X              /* second byte is a bit field.
  1329. X               *       1 = double-underline (default single),
  1330. X               *       2 = underline spaces (default don't)
  1331. X               */
  1332. X              unsupported(SetUnderlineMode);
  1333. X              verify(0xDA); break;
  1334. X
  1335. X   case 0xDB:                                   /* Set sheet feeder bin */
  1336. X              gobble(1); process1(SetBin, igetc());
  1337. X              verify(0xDB); break;
  1338. X
  1339. X   /* We ignore these codes, since they are followed by an 0x0C or an 0x8C */
  1340. X   case 0xDC: gobble(7); verify(0xDC); break;      /* End-of-page codes */
  1341. X
  1342. X   case 0xDD: gobble(22);                             /* define columns */
  1343. X              unsupported(DefineColumn);
  1344. X              verify(0xDD);
  1345. X
  1346. X   case 0xDE: environment_status = 0;         /* End indented paragraph */
  1347. X              gobble(2); process0(eIndent); verify(0xDE); break;
  1348. X
  1349. X   case 0xDF:                                   /* invisible characters */
  1350. X              gobble_until(0xDF);
  1351. X              break;
  1352. X
  1353. X   case 0xE0:                              /* Doubly-indented paragraph */
  1354. X              leave_environment(0);
  1355. X              gobble(1); process1(DIndent, igetc()); verify(0xE0);
  1356. X              environment_status = eIndent; break;
  1357. X
  1358. X   case 0xE1: process0((unsigned char)igetc()); verify(0xE1); break;
  1359. X                                                       /* IBM character */
  1360. X
  1361. X   case 0xE2: handle_note(); break;              /* footnote or endnote */
  1362. X
  1363. X   case 0xE3: gobble(74+74);                     /* footnote attributes */
  1364. X              unsupported(SetFootnoteAttributes);
  1365. X              verify(0xE3);
  1366. X              break;
  1367. X
  1368. X   case 0xE4: gobble(2); /* old */               /* set footnote number */
  1369. X              /* bit 7 of second byte doesn't count, and the value
  1370. X               * is offset by one.
  1371. X               */
  1372. X              c = igetc() & 0x3f;
  1373. X              c = (c << 7) + (igetc() & 0x7f);
  1374. X              process1(SetFnNum, 1 + c);
  1375. X              verify(0xE4);
  1376. X              break;
  1377. X
  1378. X   case 0xE5:                              /* paragraph numbering style */
  1379. X              gobble(7+7+7+7);
  1380. X              unsupported(SetParagraphNumberingStyle);
  1381. X              verify(0xE5);
  1382. X              break;
  1383. X
  1384. X   case 0xE6:                                       /* paragraph number */
  1385. X              gobble(2+7);
  1386. X              unsupported(NumberedParagraph);
  1387. X              verify(0xE6);
  1388. X              break;
  1389. X
  1390. X   case 0xE9:                                      /* begin marked text */
  1391. X              gobble(6);
  1392. X              unsupported(BeginMarkedText);
  1393. X              verify(0xE9);
  1394. X              break;
  1395. X
  1396. X   case 0xEA:                                        /* end marked text */
  1397. X              unsupported(EndMarkedText);
  1398. X              gobble_until(0xEA);
  1399. X              break;
  1400. X
  1401. X   case 0xEB:                                     /* define marked text */
  1402. X              gobble(30);
  1403. X              unsupported(DefineMarkedText);
  1404. X              verify(0xEB);
  1405. X              break;
  1406. X
  1407. X   case 0xEC:                                      /* define index mark */
  1408. X              gobble(2);
  1409. X              unsupported(DefineIndexMark);
  1410. X              verify(0xEC);
  1411. X              break;
  1412. X
  1413. X   case 0xED:                                   /* Table of authorities */
  1414. X              unsupported(DefineIndexMark);
  1415. X              gobble_until(0xED);
  1416. X              break;
  1417. X   case 0xEE:                                   /* paragraph number def */
  1418. X              gobble(42);
  1419. X              unsupported(SetParagraphNumberingStyle);
  1420. X              verify(0xEE);
  1421. X              break;
  1422. X
  1423. X   case 0xEF:                                       /* paragraph number */
  1424. X              gobble(16);
  1425. X              unsupported(NumberedParagraph);
  1426. X              verify(0xEF);
  1427. X              break;
  1428. X
  1429. X   case 0xF1: gobble(32 + 20);                          /* Tab settings */
  1430. X              handle_extended_tabs();
  1431. X              verify(0xF1);
  1432. X              break;
  1433. X
  1434. X   case 0xF3:                                      /* column definition */
  1435. X              gobble(98);
  1436. X              unsupported(DefineColumn);
  1437. X              verify(0xF3);
  1438. X              break;
  1439. X
  1440. X
  1441. X   case 0xB2:
  1442. X   case 0xB3:
  1443. X   case 0xB4:
  1444. X   case 0xB5:
  1445. X   case 0xB6:
  1446. X   case 0xB7:
  1447. X   case 0xB8:
  1448. X   case 0xB9:
  1449. X   case 0xBA:
  1450. X
  1451. X   case 0xF0:
  1452. X
  1453. X   case 0xF2:
  1454. X   case 0xF4:
  1455. X   case 0xF5:
  1456. X   case 0xF6:
  1457. X   case 0xF7:
  1458. X   case 0xF8:
  1459. X   case 0xF9:
  1460. X   case 0xFA:
  1461. X   case 0xFB:
  1462. X   case 0xFC:
  1463. X   case 0xFD:
  1464. X   case 0xFE: unsupported(UnknownCode);  break;      /* undefined codes */
  1465. X
  1466. X   case 0xFF: handle_FF(); break;
  1467. X
  1468. X   default: process0(c); break;
  1469. X  }
  1470. X  return 1;
  1471. X}
  1472. X
  1473. X/* Now do the other Useful Function.
  1474. X */
  1475. Xvoid process_input(void)
  1476. X{
  1477. X  process0(BEGIN);
  1478. X  while (process_token()) do_nothing;
  1479. X  process0(END);
  1480. X}
  1481. X
  1482. X
  1483. X/************************************************************************/
  1484. X/* The main program                                                     */
  1485. X/************************************************************************/
  1486. X
  1487. X/* First, a pretty little function which tries to open a file and
  1488. X * complains loudly if it cannot.
  1489. X */
  1490. X
  1491. XFILE *efopen(const char *s, const char *m)
  1492. X{
  1493. X  FILE *fp = fopen(s, m);
  1494. X
  1495. X  if (fp == NULL) {
  1496. X    fprintf(stderr, "Error: Cannot open %s", s);
  1497. X    if (errno > 0 && errno < sys_nerr)
  1498. X        fprintf(stderr, " (%s)\n", s, sys_errlist[errno]);
  1499. X    fprintf(stderr, "\n");
  1500. X    exit(1);
  1501. X  }
  1502. X
  1503. X  return fp;
  1504. X}
  1505. X
  1506. X#include "dopen.c"            /* ickiness with file opening */
  1507. X
  1508. X/* Our main program does very little, really.
  1509. X *
  1510. X * After checking the command line, it proceeds to open the descriptor
  1511. X * file in text mode, and the input file in binary mode.
  1512. X * It then calls our two Useful Functions in turn, closing each file
  1513. X * after it has served its purpose.
  1514. X */
  1515. X
  1516. Xint Cdecl main(int argc, char **argv)
  1517. X{
  1518. X  while (--argc && **++argv == '-') {
  1519. X    while (*++*argv) switch (**argv) {
  1520. X    case 's': silent = 1; break;
  1521. X    case 'n': blipinterval = atoi(&argv[0][1]); goto finarg;
  1522. X    default:  goto usage;
  1523. X    }
  1524. Xfinarg: ;
  1525. X  }
  1526. X  blipcount = blipinterval;
  1527. X
  1528. X  if (argc != 2) {
  1529. Xusage:
  1530. X    fprintf(stderr, "usage: wp2x descriptor input > output\n");
  1531. X    exit(2);
  1532. X  }
  1533. X
  1534. X  dopen(argv[0]);
  1535. X  input = efopen(argv[1], "rb");
  1536. X
  1537. X  do_descriptor_file();
  1538. X  fclose(descriptor);
  1539. X
  1540. X  process_input();
  1541. X  fclose(input);
  1542. X  return 0;
  1543. X}
  1544. END_OF_FILE
  1545. if test 51514 -ne `wc -c <'wp2x.c'`; then
  1546.     echo shar: \"'wp2x.c'\" unpacked with wrong size!
  1547. fi
  1548. # end of 'wp2x.c'
  1549. fi
  1550. echo shar: End of archive 3 \(of 3\).
  1551. cp /dev/null ark3isdone
  1552. MISSING=""
  1553. for I in 1 2 3 ; do
  1554.     if test ! -f ark${I}isdone ; then
  1555.     MISSING="${MISSING} ${I}"
  1556.     fi
  1557. done
  1558. if test "${MISSING}" = "" ; then
  1559.     echo You have unpacked all 3 archives.
  1560.     rm -f ark[1-9]isdone
  1561. else
  1562.     echo You still need to unpack the following archives:
  1563.     echo "        " ${MISSING}
  1564. fi
  1565. ##  End of shell archive.
  1566. exit 0
  1567.  
  1568. exit 0 # Just in case...
  1569.